package smtpserver

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/cloudwego/netpoll"
	"github.com/nosch/smtpoll/logger"
)

// NetpollServer netpoll 实现的服务器
type NetpollServer struct {
	options    *ServerOptions
	handler    MessageHandler
	eventLoop  netpoll.EventLoop
	wg         sync.WaitGroup
	sessionMap sync.Map
	stopCh     chan struct{} // 用于通知停止接受新连接
}

// NewNetpollServer 创建新的 netpoll 服务器
func NewNetpollServer(options *ServerOptions, handler MessageHandler) *NetpollServer {
	return &NetpollServer{
		options: options,
		handler: handler,
		stopCh:  make(chan struct{}),
	}
}

// Run 运行服务器
func (s *NetpollServer) Run() error {
	if s.options == nil {
		return fmt.Errorf("server options is nil")
	}

	// 为每个端口创建监听器
	for _, port := range s.options.Ports {
		addr := fmt.Sprintf("%s:%d", s.options.Host, port)
		logger.LogInfo(context.Background(), "Creating netpoll listener", "addr", addr)

		// 添加详细的日志来诊断问题
		logger.LogInfo(context.Background(), "Attempting to create listener",
			"addr", addr,
			"host", s.options.Host,
			"port", port)

		listener, err := netpoll.CreateListener("tcp", addr)
		if err != nil {
			logger.LogError(context.Background(), "Failed to create listener",
				"addr", addr,
				"error", err,
				"error_type", fmt.Sprintf("%T", err))
			return fmt.Errorf("failed to create listener: %v", err)
		}

		if listener == nil {
			logger.LogError(context.Background(), "Listener is nil",
				"addr", addr,
				"host", s.options.Host,
				"port", port)
			return fmt.Errorf("listener is nil for addr: %s", addr)
		}

		// 定义回调函数
		onRequest := func(ctx context.Context, conn netpoll.Connection) error {
			select {
			case <-s.stopCh:
				return fmt.Errorf("server is shutting down")
			default:
				if conn == nil {
					return fmt.Errorf("connection is nil")
				}

				value, ok := s.sessionMap.Load(conn)
				if !ok {
					logger.LogError(ctx, "Session not found for connection", "remote_addr", conn.RemoteAddr().String())
					// 创建新会话
					adapter := NewNetpollConnAdapter(conn)
					session := NewSession(adapter, s.handler, NewDefaultAuthSource())
					s.sessionMap.Store(conn, session)
					value = session
				}

				session := value.(*Session)
				reader := conn.Reader()
				if reader == nil {
					logger.LogError(session.ctx, "Reader is nil")
					s.sessionMap.Delete(conn)
					conn.Close()
					return fmt.Errorf("reader is nil")
				}

				// 直接使用 netpoll 的 Reader 接口
				readerAdapter := NewNetpollReaderAdapter(reader)
				if err := session.ProcessConnection(readerAdapter); err != nil {
					logger.LogError(session.ctx, "Session processing failed", "error", err)
					s.sessionMap.Delete(conn)
					conn.Close()
					return err
				}

				return nil
			}
		}

		onConnect := func(ctx context.Context, conn netpoll.Connection) context.Context {
			select {
			case <-s.stopCh:
				conn.Close()
				return ctx
			default:
				if conn == nil {
					logger.LogError(ctx, "Connection is nil in onConnect")
					return ctx
				}

				remoteAddr := conn.RemoteAddr()
				localAddr := conn.LocalAddr()
				if remoteAddr == nil || localAddr == nil {
					logger.LogError(ctx, "Invalid connection addresses")
					return ctx
				}

				logger.LogInfo(ctx, "New connection established",
					"remote_addr", remoteAddr.String(),
					"local_addr", localAddr.String())

				// 创建适配器
				adapter := NewNetpollConnAdapter(conn)
				if adapter == nil {
					logger.LogError(ctx, "Failed to create connection adapter")
					return ctx
				}

				// 创建会话
				session := NewSession(adapter, s.handler, NewDefaultAuthSource())
				if session == nil {
					logger.LogError(ctx, "Failed to create session")
					return ctx
				}

				// 存储会话
				s.sessionMap.Store(conn, session)

				return ctx
			}
		}

		// 创建事件循环
		eventLoop, err := netpoll.NewEventLoop(
			netpoll.OnRequest(onRequest),
			netpoll.WithOnConnect(onConnect),
			netpoll.WithReadTimeout(s.options.ReadTimeout),
			netpoll.WithWriteTimeout(s.options.WriteTimeout),
		)
		if err != nil {
			logger.LogError(context.Background(), "Failed to create event loop", "addr", addr, "error", err)
			return fmt.Errorf("failed to create event loop: %v", err)
		}

		if eventLoop == nil {
			logger.LogError(context.Background(), "Event loop is nil", "addr", addr)
			return fmt.Errorf("event loop is nil for addr: %s", addr)
		}

		s.eventLoop = eventLoop
		logger.LogInfo(context.Background(), "Netpoll SMTP server listening", "addr", addr)

		// 启动事件循环
		go func(loop netpoll.EventLoop, l netpoll.Listener) {
			defer func() {
				if r := recover(); r != nil {
					logger.LogError(context.Background(), "Event loop panic", "error", r)
				}
			}()

			if err := loop.Serve(l); err != nil {
				logger.LogError(context.Background(), "Error serving", "addr", addr, "error", err)
			}
		}(eventLoop, listener)
	}

	return nil
}

// Stop 停止服务器
func (s *NetpollServer) Stop() error {
	logger.LogInfo(context.Background(), "Starting server shutdown")

	// 1. 首先通知停止接受新连接
	close(s.stopCh)

	// 2. 关闭所有活动连接
	s.sessionMap.Range(func(key, value any) bool {
		if conn, ok := key.(netpoll.Connection); ok {
			if session, ok := value.(*Session); ok {
				logger.LogInfo(session.ctx, "Closing connection during shutdown",
					"remote_addr", conn.RemoteAddr().String())
				// 发送关闭消息
				session.respond(CODE_BYE, "Server shutting down")
				// 关闭连接
				conn.Close()
			}
		}
		return true
	})

	// 3. 关闭事件循环
	if s.eventLoop != nil {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		if err := s.eventLoop.Shutdown(ctx); err != nil {
			logger.LogError(ctx, "Failed to shutdown event loop", "error", err)
		}
	}

	logger.LogInfo(context.Background(), "Server shutdown completed")
	return nil
}

// GetOptions 返回服务器配置选项
func (s *NetpollServer) GetOptions() *ServerOptions {
	return s.options
}
